package com.androwit.engine.mapping;

import java.io.Serializable;
import java.util.Map;

import com.androwit.engine.mapping.converter.str.DateConverter;
import com.androwit.engine.mapping.converter.str.IntegerConverter;
import com.androwit.engine.mapping.converter.str.StringAppenderConverter;

/**
 * Defines fields corresponding to row values and creates the instances that will hold the typed java values: see {@link MappingFieldsDefiner} for detailed
 * documentation
 * 
 * @author Zied Hamdi Founder of http://1vu.fr, Zied Hamdi founder of http://into-i.fr
 * 
 * 
 */
public class FieldsDefinerMock implements MappingFieldsDefiner<Object, Integer, String> {

	static OneSensValueConverter<Serializable, String> FICTIVE_VALUE_CONVERTER = new OneSensValueConverter<Serializable, String>() {

		@Override
		public Serializable setFromTarget(String value, Object instance, MappingField<Serializable, ?, String> field) throws Exception {
			return null;
		}

		@Override
		public Serializable fromConverted(String value) throws Exception {
			return null;
		}

		@Override
		public String convert(Serializable value) throws Exception {
			return null;
		}
	};

	/**
	 * Let's define the columns we will encounter, it can but doesn't have to be an enumeration. You must only implement {@link MappingField} or use
	 * {@link BasicMappingField}
	 * 
	 * @author Zied Hamdi Founder of http://1vu.fr, Zied Hamdi founder of http://into-i.fr
	 * 
	 */
	enum Fields implements MappingField<Object, Integer, String> {
		FICTIVE_VALUE(FICTIVE_VALUE_CONVERTER, "type", true), INT_VALUE(new IntegerConverter(), "intValue"), DATE_VALUE(new DateConverter(ParserTest.DATE_FORMAT),
				"dateValue"), STRING_PART_1(new StringAppenderConverter(" "), "str", true), STRING_PART_2(new StringAppenderConverter(" "), "str", true);

		private Converter<?, String> converter;

		private Fields(Converter<?, String> converter, String name) {
			this(converter, name, false);
		}

		private Fields(Converter<?, String> converter, String name, boolean handleSpecifically) {
			this.converter = converter;
			this.name = name;
			this.handleSpecifically = handleSpecifically;
		}

		private String name;
		private boolean handleSpecifically;

		/**
		 * can be null if your java property is a string, otherwise return a converter for your property type
		 */
		@SuppressWarnings({ "rawtypes", "unchecked" })
		@Override
		public Converter getConverter() {
			return converter;
		}

		/**
		 * java property name: can be deeper than the first level for example: <code>"user.address.city"</code> to call
		 * <code>getUser().getAddress().setCity(<i>value</i>)</code> (you just have to check the inner objects are not null)
		 */
		@Override
		public String getName() {
			return name;
		}

		/**
		 * don't try to inject this column value to the java instance if returns false
		 */
		@Override
		public boolean handledSpecifically() {
			return handleSpecifically;
		}

		@Override
		public Integer getKey() {
			return ordinal();
		}

	}

	/**
	 * create the java instance representing the current row (optionally you can analyse the row content to return the appropriate instance)
	 */
	@Override
	public Object createInstance(Map<Integer, String> values) {
		return new SimpleObjectMock();
	}

	/**
	 * used to write csv files only
	 */
	@Override
	public MappingField<Object, Integer, String>[] getMappingFields(Object toPersist) {
		return Fields.values();
	}

	/**
	 * return the definitions of the columns corresponding to values: you must return an array with the same size as <code>values</code>
	 */
	@Override
	public MappingField<Object, Integer, String>[] getMappedFields(Map<Integer, String> values) {
		return getMappingFields(null);
	}

}